#ifndef GENERAL_HPP
#define GENERAL_HPP

#include "attack.hpp"
#include "raider.hpp"

#include "igeneral.hpp"
#include "Location.h"
#include "bitmap.hpp"
#include "antlist.hpp"
#include "defense.hpp"
#include "farming.hpp"
#include "exploration.hpp"

#include "army.hpp"

#include <set>


class generalbase
  : public igeneral
{
protected:
  int _rows;
  int _cols;
  int _turns;
  int _players;
  double _attackradius;
  double _spawnradius;
  double _viewradius;
  double _loadtime;
  double _turntime;
  int64_t _seed;

protected:
  int _turn;
  bool _gameover;
  std::vector<advice> _forces;

public:
  void loadtime(double value) { _loadtime = value; }
  void turntime(double value) { _turntime = value; }
  void rows(int value){ _rows = value; }
  void cols(int value){ _cols = value; }
  void turns(int value){ _turns = value; }
  void seed(int64_t value){ _seed = value; }
  void viewradius(double value){ _viewradius = value; }
  void attackradius(double value){ _attackradius = value; }
  void spawnradius(double value){ _spawnradius = value; }
  void ready()
  {
    // включить таймер загрузки
  }

  virtual std::vector<advice>& forces() 
  {
    return _forces;
    
  }
  // В процессе загрузки хода
  void players(int value){ _players = value; }
  void scores(const std::vector<double>& ) {}
  
  virtual double viewradius() const
  {
    return _viewradius;
  }

  virtual double attackradius() const
  {
    return _attackradius;
  }
  
  virtual location area() const 
  {
    return location(_rows, _cols);
  };

  void go()
  {
    // включить таймер хода
  }

};

class general
  : public generalbase
{
  typedef bitmap bitmap_type;


/// ///////////////////////////////
  typedef std::vector<location> location_list;
  typedef std::vector<item> item_list;

  item_list _antlist;
  item_list _myantlist;
  item_list _enemyantlist;
  item_list _hilllist;
  location_list _foodlist;

  bitmap_type _water;
  // Видимая на данный момент ( 1-невидимая область )
  bitmap_type _ivisible;
  // Изученная ( 1-неиследованная область )
  bitmap_type _istudy;

  bitmap_type _food;
  bitmap_type _myants;
  bitmap_type _enemyants;
  bitmap_type _myhills;
  bitmap_type _enemyhills;
  
  bitmap_type _attack0;
  bitmap_type _attack1;
  bitmap_type _attack2;
  
  army _army_test;
  attack _attack;
  defense _defense;
public:
  
  general()
  {
    _turn = -1;
  }

/// ////////////////////////////////
/// ////////////////////////////////
/// ////////////////////////////////
  virtual const std::vector<location>& foodlist() const
  {
    return _foodlist;
  }
  virtual const std::vector<item>& antlist() const
  {
    return _antlist;
  }

  virtual const std::vector<item>& myantlist() const
  {
    return _myantlist;
  }
  
  virtual const std::vector<item>& enemyantlist() const
  {
    return _enemyantlist;
  }

  virtual const std::vector<item>& hilllist() const
  {
    return _hilllist;
  }

  virtual const bitmap& food() const
  {
    return _food;
  }
  virtual const bitmap& myants() const
  {
    return _myants;
  }
  virtual const bitmap& enemyants() const
  {
    return _enemyants;
  }
  
  virtual const bitmap& myhills() const
  {
    return _myhills;
  }
  virtual const bitmap& enemyhills() const
  {
    return _enemyhills;
  }
  
  virtual const bitmap& ivisible() const
  {
    return _ivisible;
  }
  
  virtual const bitmap& istudy() const
  {
    return _istudy;
  }
  
  virtual const bitmap& water() const
  {
    return _water;
  }

  virtual const bitmap& enemyattack(int w) const
  {
    if (w==0) return _attack0;
    if (w==1) return _attack1;
    return _attack2;
  }
  
  virtual int turn() const 
  {
    return _turn;
  };


  
/// ////////////////////////////////
/// ////////////////////////////////
/// ////////////////////////////////
  
  void show(std::ostream& os)
  {
    
    os << "TURN " << _turn << std::endl;
    _ivisible.show( os, "GENERAL visible");
    /*_attack.show(os);
    _attack2.show(os);  
    */
    /*_myants.show(os, "GENERAL MYANTS");
    _army_test.show(os);
    */
    
  }

  // Один раз в самом начале после установки параметров
  void initialize()
  {
    _water.create(_rows, _cols, 0);
    _ivisible.create(_rows, _cols, 1);
    _istudy.create(_rows, _cols, 1);
    _food.create(_rows, _cols, 0);
    _myants.create(_rows, _cols, 0);
    _enemyants.create(_rows, _cols, 0);
    _myhills.create(_rows, _cols, 0);
    _enemyhills.create(_rows, _cols, 0);
    
    _attack0.create(_rows, _cols, 0);
    _attack1.create(_rows, _cols, 0);
    _attack2.create(_rows, _cols, 0);

    
    _army_test.initialize(_rows, _cols);
    _attack.initialize(_rows, _cols);
    _defense.initialize(_rows, _cols);
    
  }

  // В начале каждого хода
  void setup()
  {
  }

  void turn( int t )
  {
    if ( (_turn + 1) != t ) 
      throw std::logic_error( "invalid turn" );
    _turn = t;
  }

  void viewradius( double vr)
  {
    _viewradius = vr;
  }

  void add_water(location loc)
  {
    _water.set( loc );
  }

  // 0 - свой муравей > 0 враг
  void add_ant(location loc, int enemy)
  {
    _ivisible.reset(loc, _viewradius);
    _istudy.reset(loc, _viewradius);
    _antlist.push_back( item(loc, enemy) );

    if ( enemy == 0 )
    {
      _myantlist.push_back( item(loc, enemy) );
      _myants.set(loc);
    }
    else
    {
      _enemyantlist.push_back( item(loc, enemy) );
      _attack0.set(loc, _attackradius );
      _attack1.set(loc, _attackradius + 1);
      _attack2.set(loc, _attackradius * 2);

      _enemyants.set(loc);
      
            //!!!
      if ( _foodlist.size() < 4 ) 
      {
      /*  _foodlist.push_back(loc);
        _food.set(loc);*/
      }
      

    }
  }

  void add_dead(location loc, int enemy)
  {
  }

  void add_hill(location loc, int enemy)
  {
    _hilllist.push_back( item(loc, enemy) );

    if ( !enemy )
      _myhills.set(loc);
    else
    {
      _enemyhills.set(loc);
      //!!!
      /*
      _foodlist.push_back(loc);
      _food.set(loc);
      */

    }
  }

  void add_food(location loc)
  {
    _foodlist.push_back(loc);
    _food.set(loc);
  }

  // рекогносцировка
  // Вызывается в начале каждого турнира
  // ПОСЛЕ добавления муравьев и пр. целей
  void reconnaissance()
  {

    if ( _viewradius < 0.9 )
      throw std::logic_error( "invalid view radius" );
    
    _forces.assign(_myantlist.begin(), _myantlist.end());
    std::sort(_forces.begin(), _forces.end());

    _army_test.reconnaissance(this);
    _defense.reconnaissance(this);
    _attack.reconnaissance(this);
    

  }

  location get_new_location(const location &loc, int direction)
  {
    if ( direction == -1 )
      return loc;
    return location( (loc.row + my::DIRECTIONS[direction][0] + _rows) % _rows,
                     (loc.col + my::DIRECTIONS[direction][1] + _cols) % _cols );
  };

  /// Основной цикл обработки 
  void make_move()
  {
    bitmap bm;
    std::vector<advice>::iterator beg = _forces.begin();
    std::vector<advice>::iterator end = _forces.end();
    
    for (;beg!=end;++beg)
    {
      std::cerr << beg->direction << std::endl;
      if (beg->direction!=-1)
      {
        location cur = location::move( *beg, beg->direction, location(_rows, _cols ));
        if (cur && !_water.get(cur) && !bm.get(cur) )
        {
          std::cout << "o " << beg->row << " " << beg->col << " " << my::CDIRECTIONS[beg->direction] << std::endl;
          /*_myants.reset(*beg);
          _myants.set(cur);
          */
        }
        bm.set(cur);
      }
    }

    return;
    for(;!_myantlist.empty();)
    {
      advice adv = _attack.candidate();
      if (!adv)
        adv = _army_test.candidate();
      if ( !adv /*|| adv.direction == -1*/)
      {
        location loc = *_myantlist.begin();
        static_cast<location&>(adv) = loc;
        adv.direction = -1;
        for (int i = rand()%2; i < my::TDIRECTIONS; ++i)
        {
          int d = i;
          location cur = location::move( loc, d, location(_rows, _cols ));
          if (cur && !_water.get(cur) && !_myants.get(cur) )
          {
            adv.direction = d;
            break;
          }
        }
      }

      if (adv && adv.direction != -1)
      {
        std::cout << "o " << adv.row << " " << adv.col << " " << my::CDIRECTIONS[adv.direction] << std::endl;
      }
      if (adv )
      {
        location loc =  get_new_location(adv, adv.direction);
        _army_test.committed(adv, loc);
        _attack.committed(adv, loc);
        _myantlist.erase(std::find(_myantlist.begin(), _myantlist.end(), adv));
        _myants.reset(adv);
        _myants.set(loc);
      }

    }
    
    
  }

  void finalize()
  {
    _myantlist.clear();
    _enemyantlist.clear();
    
    _ivisible.clear(1);
    _food.clear(0);
    _myhills.clear(0);
    _enemyhills.clear(0);
    _myants.clear(0);
    _enemyants.clear(0);
    
    _antlist.clear();
    _hilllist.clear();
    _foodlist.clear();
    
    _attack0.clear(0);
    _attack1.clear(0);
    _attack2.clear(0);
    
  }


  void gameover()
  {
  }

};

#endif
